// 日志器模块
// 1.抽象日志器基类
// 2.派生出不同的子类（同步&&异步日志器类）
#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* See feature_test_macros(7) */
#endif
#include <stdarg.h>
#include <thread>
#include <atomic>
#include <cstdlib>
#include "logs.hpp"
#include "unil.hpp"
#include "sink.hpp"
#include "format.hpp"
#include "hoop.hpp"
#include <mutex>
#include <atomic>
#include <unordered_map>
namespace TopLog
{
    //日志器
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, Logs::Value level,
               Formatter::ptr &formatter, vector<Logsink::ptr> &sinks)
            : _logger_name(logger_name), _limit_level(level), _formatter(formatter), _sinks(sinks.begin(), sinks.end()){};

        const string &loggername()
        {
            return _logger_name;
        }


        void unknowns(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断日志等级是否可以输出
            if (Logs::Value::UNKNOWNS < _limit_level)
            {
                return;
            }

            // 2.格式化字符串和不定参数字符串组织，得到消息字符串
            va_list ap;
            char *s;
            va_start(ap, fmt);

            int n = vasprintf(&s, fmt.c_str(), ap); // 计算好长度存到s中，  如果为空，返回-1 否则返回计算好长度
            if (n != -1)
            {
                printf(s);
            }
            va_end(ap);

            serialize(Logs::Value::UNKNOWNS, file, line, s);
            free(s);
        }


        // 完成日志构造，消息对象进行格式化，得到格式化后的日志字符串
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断日志等级是否可以输出
            if (Logs::Value::DEBUG < _limit_level)
            {
                return;
            }
            // 2.格式化字符串和不定参数字符串组织，得到消息字符串
            va_list ap;
            char *s;
            va_start(ap, fmt);

            int n = vasprintf(&s, fmt.c_str(), ap); // 计算好长度存到s中，  如果为空，返回-1 否则返回计算好长度
            if (n != -1)
            {
                printf(s);
            }
            va_end(ap);

            serialize(Logs::Value::DEBUG, file, line, s);
            free(s);
        }




        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断日志等级是否可以输出
            if (Logs::Value::INFO < _limit_level)
            {
                return;
            }
            // 2.格式化字符串和不定参数字符串组织，得到消息字符串
            va_list ap;
            char *s;
            va_start(ap, fmt);

            int n = vasprintf(&s, fmt.c_str(), ap); // 计算好长度存到s中，  如果为空，返回-1 否则返回计算好长度
            if (n != -1)
            {
                printf(s);
            }
            va_end(ap);

            serialize(Logs::Value::INFO, file, line, s);
            free(s);
        }



        void warning(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断日志等级是否可以输出
            if (Logs::Value::WARNING < _limit_level)
            {
                return;
            }
            // 2.格式化字符串和不定参数字符串组织，得到消息字符串
            va_list ap;
            char *s;
            va_start(ap, fmt);

            int n = vasprintf(&s, fmt.c_str(), ap); // 计算好长度存到s中，  如果为空，返回-1 否则返回计算好长度
            if (n != -1)
            {
                printf(s);
            }
            va_end(ap);

            serialize(Logs::Value::WARNING, file, line, s);
            free(s);
        }





        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断日志等级是否可以输出
            if (Logs::Value::ERROR < _limit_level)
            {
                return;
            }
            // 2.格式化字符串和不定参数字符串组织，得到消息字符串
            va_list ap;
            char *s;
            va_start(ap, fmt);

            int n = vasprintf(&s, fmt.c_str(), ap); // 计算好长度存到s中，  如果为空，返回-1 否则返回计算好长度
            if (n != -1)
            {
                printf(s);
            }
            va_end(ap);

            serialize(Logs::Value::ERROR, file, line, s);
            free(s);
        }



        
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断日志等级是否可以输出
            if (Logs::Value::FATAL < _limit_level)
            {
                return;
            }
            // 2.格式化字符串和不定参数字符串组织，得到消息字符串
            va_list ap;
            char *s;
            va_start(ap, fmt);

            int n = vasprintf(&s, fmt.c_str(), ap); // 计算好长度存到s中，  如果为空，返回-1 否则返回计算好长度
            if (n != -1)
            {
                printf(s);
            }
            va_end(ap);

            serialize(Logs::Value::FATAL, file, line, s);
            free(s);
        }

        void off(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1.判断日志等级是否可以输出
            if (Logs::Value::OFF < _limit_level)
            {
                return;
            }
            // 2.格式化字符串和不定参数字符串组织，得到消息字符串
            va_list ap;
            char *s;
            va_start(ap, fmt);

            int n = vasprintf(&s, fmt.c_str(), ap); // 计算好长度存到s中，  如果为空，返回-1 否则返回计算好长度
            if (n != -1)
            {
                printf(s);
            }
            va_end(ap);

            serialize(Logs::Value::OFF, file, line, s);
            free(s);
        }

    protected:
        void serialize(Logs::Value level, const std::string &file, size_t line, char *str)
        {
            // 3.构造消息
            LogMsg msg(line, _logger_name, file, str, level);

            // 4.通过格式化工具对LogMsg进行格式化，得到格式化字符串后的日志字符串
            std::stringstream ss;
            _formatter->format(ss, msg);

            // 5.日志落地
            log(ss.str().c_str(), ss.str().size());
        }

        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mutex;
        std::string _logger_name;              // 日志器名称
        std::atomic<Logs::Value> _limit_level; // 保证访问线程安全
        Formatter::ptr _formatter;             // 格式化
        std::vector<Logsink::ptr> _sinks;      // 输出方向
    };

    // 同步日志落地方向
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name, Logs::Value level,
                   Formatter::ptr &formatter, vector<Logsink::ptr> &sinks)
            : Logger(logger_name, level, formatter, sinks){};

    protected:
        void log(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &e : _sinks)
            {
                e->log(data, len);
            }
        }
    };

    // 异步日志落地方向
    class ASyncLogger : public Logger
    {
    public:
        ASyncLogger(const std::string &logger_name, Logs::Value level,
                    Formatter::ptr &formatter, vector<Logsink::ptr> &sinks, AsyncType looper_type)
            : Logger(logger_name, level, formatter, sinks), _looper(std::make_shared<AsyncTask>(std::bind(&ASyncLogger::rolllog, this, std::placeholders::_1))){};
        // 通过构建智能指针来实现落地缓冲区， bind 把函数的传参绑定在一起
    protected:
        void log(const char *data, size_t len)
        {
            _looper->push(data, len);
        }
        void rolllog(Buffer &buf)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;

            for (auto &e : _sinks)
            {
                e->log(buf.begin(), buf.readAbleSize());
            }
        }

    protected:
        AsyncTask::ptr _looper; // 管理异步工作器指针
    };

    // 使用建造者模式来建造日志器，而不要让用户构造日志器，简单化使用日志器
    // 1.抽象一个日志器建造者类
    // 2.设置日志器类型
    // 3.将不同类型日子其的创建放在同一个日志器建造者类中完成
    // 4.派生出具体的建造者类， 局部日志建造者类 & 全局日志建造者
    enum LoggerType
    {
        LOGGER_SYNC, // 同步日志器
        LOGGER_ASYNC // 异步日志器
    };
    // 建造者基类
    class LoggerBuilder
    {
    public:
    using ptr = shared_ptr<LoggerBuilder>;
        LoggerBuilder() : _logger_type(LoggerType::LOGGER_SYNC), _limit_level(Logs::Value::WARNING), _safe_type(AsyncType::ASYNC_SAFE) {}
        void buildLoggerType(LoggerType Type)
        {
            _logger_type = Type;
            std::cout << _logger_type << endl;
        }

        void buildUnSyncsafe()
        {
            _safe_type = AsyncType::ASYNC_UNSAFE;
        }

        void buildLoggerLevel(Logs::Value level)
        {
            _limit_level = level;
        }

        void buildLoggerName(const std::string &name)
        {
            _logger_name = name;
        }

        void buildLoggerFamtter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }

        template <typename SinkType, typename... Args>
        void buildSink(Args &&...args)
        {
            Logsink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        virtual Logger::ptr build() = 0;

    protected:
        LoggerType _logger_type;
        std::string _logger_name;
        AsyncType _safe_type; // 安全设置
        Logs::Value _limit_level;
        Formatter::ptr _formatter;        // 格式化
        std::vector<Logsink::ptr> _sinks; // 输出方向
    };
    // 局部建造者
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(_logger_name.empty() == false); // 唯一标识
            if (_formatter.get() == nullptr)       // 获取指针
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            Logger::ptr _logger;
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                // 建造异步日志
                _logger = std::make_shared<ASyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _safe_type);
            }
            else
            {
                _logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks); // 建造同步日志
            }
            return _logger;
        }
    };

    // 单例类
    class LoggerManages
    {

    public:
        static LoggerManages &GetInstance()
        {
            // c++11 静态局部变量在编译时保证了线程安全
            static LoggerManages lm;
            return lm;
        }

        // 添加日志器
        void addLogger(Logger::ptr &_logger)
        {
            if (hasLogger(_logger->loggername())) //如果存在就返回
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(_logger->loggername(), _logger));
        }
        // 判断日志器是否存在
        bool hasLogger(const std::string name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }
            return true;
        }

        // 获取日志器
        Logger::ptr getLogger(const std::string name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return Logger::ptr();
            }
            return it->second;
        }
        // 获取默认日志器
        Logger::ptr getLoggerroot()
        {
            std::unique_lock<mutex> lock(_mutex);
            return _root_logger;
        }

    private:
        LoggerManages()
        {
            // 构建好默认日志器
            // 只能构建局部建造者 不然在构建_root_logger时会卡住，二次构造
            std::unique_ptr<TopLog::LoggerBuilder> slb(new TopLog::LocalLoggerBuilder());
            slb->buildLoggerName("root");
            slb->buildLoggerType(LoggerType::LOGGER_SYNC);
            _root_logger = slb->build();
            _loggers.insert(std::make_pair("root", _root_logger));
        };
        LoggerManages(const LoggerManages &) = delete;
        LoggerManages &operator=(const LoggerManages &) = delete;

    private:
        std::mutex _mutex;
        Logger::ptr _root_logger;                              // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers; // 存储日志器
    };

    // 全局建造者--在本地基础上自动添加日志器
    class GloBalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(_logger_name.empty() == false); // 唯一标识 必须有名字
            if (_formatter.get() == nullptr)       // 获取格式化字符指针
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty()) // 默认落地方向
            {
                buildSink<StdoutSink>();
            }
            Logger::ptr logger;
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                // 建造异步日志
                logger = std::make_shared<ASyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _safe_type);
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks); // 建造同步日志
            }
            LoggerManages::GetInstance().addLogger(logger); // 获取句柄，然后实例化
            return logger;
        }
    };

}

#endif



